
format ELF64 executable 3
entry main

IMG_WIDTH = 800
IMG_HEIGHT = 800

segment readable executable

ENEIDA_UTIL_INCLUDE = 'CODE'
include 'util/util_amath.inc'
include 'util/util_image.inc'

; TODO: implement this
;
; "uniform float Time;"
; "uniform vec2 Resolution = vec2(800, 600);"
;
; "out vec4 Color;"
;
; "void main() {"
; "    vec2 p = (2.0 * gl_FragCoord.xy - Resolution.xy) / Resolution.y;"
; "    float tt = mod(Time, 2.0) / 2.0;"
; "    float ss = pow(tt, 0.2) * 0.5 + 0.5;"
; "    ss -= ss * 0.2 * sin(tt * 6.2831 * 5.0) * exp(-tt * 6.0);"
; "    p *= vec2(0.5, 1.5) + ss * vec2(0.5, -0.5);"
;
; "    float a = atan(p.x, p.y) / 3.141593;"
; "    float r = length(p);"
;
; "    float h = abs(a);"
; "    float d = (13.0 * h - 22.0 * h * h + 10.0 * h * h * h) / (6.0 - 5.0 * h);"
;
; "    float f = step(r, d) * pow(1.0 - r / d, 0.25);"
;
; "    Color = vec4(f, 0, 0, 1);"
; "}";

; [inout, void *, rdi] pointer to the pixel data to be shaded
; [in, float, xmm0] x pixel coordinate
; [in, float, xmm1] y pixel coordinate
shade:
    push rbx
    sub rsp,80
    movaps [rsp],xmm0
    movaps [rsp+16],xmm1
    movss xmm6,xmm0
    movss xmm7,xmm1
    ; mod(x, y) = x - y * floor(x / y)
    ; [rsp+32] = mod(time, 2.0) / 2.0
    movss xmm0,[time]
    movss xmm2,[c_2_f32]
    movss xmm1,xmm0
    divss xmm1,xmm2
    cvttss2si esi,xmm1
    movd edx,xmm1
    shr edx,31
    sub esi,edx
    cvtsi2ss xmm1,esi
    mulss xmm1,xmm2
    subss xmm0,xmm1
    divss xmm0,xmm2
    movaps [rsp+32],xmm0
    ; [rsp+48] = pow([rsp+32], 0.2) * 0.5 + 0.5
    movss xmm1,[c_0p2_f32]
    am_pow_ss
    mulss xmm0,[am_v4_f32_0p5]
    addss xmm0,[am_v4_f32_0p5]
    movaps [rsp+48],xmm0
    ; [rsp+64] = [rsp+48] * 0.2 * sin([rsp+32] * 2pi * 5.0)
    movaps xmm0,[rsp+32]
    mulss xmm0,[am_v4_f32_2pi]
    mulss xmm0,[c_5_f32]
    am_sin_ss
    mulss xmm0,[c_0p2_f32]
    mulss xmm0,[rsp+48]
    movss [rsp+64],xmm0
    
    movaps xmm0,[rsp]
    movaps xmm1,[rsp+16]
    addss xmm0,[am_v4_f32_1]
    mulss xmm0,[am_v4_f32_0p5]
    movss [rdi+8],xmm0
    addss xmm1,[am_v4_f32_1]
    mulss xmm1,[am_v4_f32_0p5]
    movss [rdi+4],xmm1
    pxor xmm0,xmm0
    movss [rdi],xmm0
    add rsp,80
    pop rbx
    ret

main:
    ; allocate space for the HDR image
    mov edi,IMG_WIDTH*IMG_HEIGHT*16
    call image_alloc
    mov [pixels_hdr],rax
    ; loop over each pixel
    mov rbx,[pixels_hdr]
    mov [y],0
      loopy:
    mov [x],0
      loopx:
    ; compute x coordinate (xmm0)
    mov eax,[x]
    add eax,eax
    sub eax,IMG_WIDTH
    cvtsi2ss xmm0,eax
    cvtsi2ss xmm2,[height]
    divss xmm0,xmm2
    ; compute y coordinate (xmm1)
    mov eax,[y]
    add eax,eax
    sub eax,IMG_HEIGHT
    cvtsi2ss xmm1,eax
    divss xmm1,xmm2
    ; compute pixel color
    mov rdi,rbx
    call shade
    ; move to the next pixel
    add rbx,16
    add [x],1
    cmp [x],IMG_WIDTH
    jne loopx
    add [y],1
    cmp [y],IMG_HEIGHT
    jne loopy
    ; allocate space for the LDR image
    mov edi,IMG_WIDTH*IMG_HEIGHT*4
    call image_alloc
    mov [pixels],rax
    ; convert HDR to LDR
    mov rdi,[pixels]
    mov rsi,[pixels_hdr]
    mov edx,IMG_WIDTH
    mov ecx,IMG_HEIGHT
    call image_hdr2ldr
    ; save the image
    mov	rdi,filename
    mov rsi,[pixels]
    mov edx,IMG_WIDTH
    mov ecx,IMG_HEIGHT
    call image_save
    ; terminate process
    mov	eax,60
    mov	edi,0
    syscall

segment readable writeable

align 4

filename db 'image_heart.tga', 0
pixels dq ?
pixels_hdr dq ?

c_0p2_f32 dd 0.2
c_2_f32 dd 2.0
c_5_f32 dd 5.0
x dd 0
y dd 0
width dd IMG_WIDTH
height dd IMG_HEIGHT
time dd 1.0

ENEIDA_UTIL_INCLUDE = 'DATA'
include 'util/util_amath.inc'
include 'util/util_image.inc'
